iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
自我挑戰組

用數據守護雙眼:生活型態對視力影響的探索性資料分析系列 第 30 篇

鐵人賽大完結!Streamlit / Gradio 互動式臨床級 Web 儀表板與 30 天全專案技術總結

  • 分享至 

  • xImage
  •  

迎來 30 天鐵人挑戰的最終篇章!將 Day 28 封裝的 eye_strain_ensemble_pipeline.joblib 與 Day 29 的即時推論邏輯,串接為具備臨床眼科質感的 互動式 Web 儀表板(Web UI Dashboard)。使用者可透過直覺的滑桿與選單輸入日常生理作息,系統即時計算 CESI 綜合疲勞指數、輸出三分類機率圖卡與動態門檻警示,並附上微觀 SHAP 處方建議。文末進行 30 天從資料清洗、統計檢定、模型迭代到生產部署的完整工程架構總回顧。


一、 實作前情境:讓機器學習走出終端機,打造臨床級友善介面
在過去 29 天中,我們完成了從底層數據挖掘到高併發 API 的所有工作:
最後一哩路(The Last Mile of Data Science):
a.醫療或健康管理專家無法直接閱讀終端機印出的 JSON 字典物件。
b.一個合格的健康評估系統,必須具備:

  • 友善輸入介面:將 0~10 的自覺評分、每日螢幕暴露時數、睡眠時數轉為直覺的拉桿與下拉選單。
  • 即時風險儀表板:直觀顯示低、中、高度風險的機率條形分佈與視覺燈號。
  • 可解釋性白話處方:即時結合 SHAP 邏輯,告訴受試者「哪項生活習慣是主要發病推手」。

2.快速原型框架選擇(Gradio):

  • 在 Colab 環境中,Gradio 能在單一 Python 區塊內同時建立 Web 前端、綁定 Pipeline 推論函數,並直接生成具備 SSL 加密的暫時性公開網址(share=True),適合快速向臨床醫師、研究團隊展示 POC 原型。

二、 撰寫 Gradio 互動式用眼疲勞健康診斷儀表板
在 Colab 中新增儲存格,安裝套件並啟動完整的前端 Web 應用:

# ==========================================
# Day 30:用眼疲勞風險即時評估互動儀表板 (Gradio)
# ==========================================

import warnings
warnings.filterwarnings('ignore')

!pip install gradio -q

import gradio as gr
import pandas as pd
import numpy as np
import joblib

# 1. 載入 Day 28 持久化模型包
MODEL_FILE = 'eye_strain_ensemble_pipeline.joblib'
try:
    package = joblib.load(MODEL_FILE)
    pipeline = package['pipeline']
    th_high = package['optimal_threshold_high']
    target_names = package['target_names']
    print(f"成功加載模型包!高風險動態判定門檻為: {th_high:.3f}")
except Exception as e:
    raise RuntimeError(f"載入模型失敗,請確認檔案是否存在: {e}")

# 2. 定義核心預測與處方生成函數
def diagnose_eye_strain(
    age, role, daily_screen_hours, sleep_hours, 
    break_frequency, eye_dryness, eye_pain, 
    headache_freq, blue_light_filter, blurred_vision
):
    # 建立輸入資料 DataFrame (完全符合 Pipeline 原始輸入規格)
    input_df = pd.DataFrame([{
        'Age': int(age),
        'Role': role,
        'Daily_Screen_Hours': float(daily_screen_hours),
        'Sleep_Hours': float(sleep_hours),
        'Break_Frequency_Per_Hour': int(break_frequency),
        'Eye_Dryness_Level': int(eye_dryness),
        'Eye_Pain_Level': int(eye_pain),
        'Headache_Frequency_Per_Week': int(headache_freq),
        'Blue_Light_Filter_Used': blue_light_filter,
        'Blurred_Vision': blurred_vision
    }])
    
    # 透過端到端管線執行即時推論
    prob = pipeline.predict_proba(input_df)[0]
    prob_low, prob_med, prob_high = prob[0], prob[1], prob[2]
    
    # 計算即時 CESI 指數 (Day 15 公式)
    safe_sleep = max(float(sleep_hours), 0.5)
    cesi_val = (float(daily_screen_hours) / safe_sleep) * (int(eye_pain) + int(eye_dryness) + 1.0)
    
    # 套用 Day 27 動態門檻判定規則
    if prob_high >= th_high:
        final_level = "高度風險 (High)"
        alert_badge = "⚠️ 【臨床警示】高度眼部疲勞風險!建議就診或強制休息!"
        box_style = "error"
    else:
        final_idx = int(np.argmax(prob[:2]))
        final_level = target_names[final_idx]
        if final_idx == 1:
            alert_badge = "🟡 【注意預防】中度用眼疲勞,需調整用眼習慣。"
            box_style = "warning"
        else:
            alert_badge = "🟢 【狀態良好】低度用眼疲勞,請繼續保持健康習慣。"
            box_style = "info"
            
    # 機率字典 (供 Gradio Label 元件繪製長條圖)
    prob_dict = {
        "低度風險 (Low)": float(prob_low),
        "中度風險 (Medium)": float(prob_med),
        "高度風險 (High)": float(prob_high)
    }
    
    # 生成臨床個人化白話處方箋
    prescription = f"""
### 📋 臨床用眼健康診斷報告
* **綜合判定結果**:**{final_level}**
* **CESI 綜合疲勞指數**:**{cesi_val:.2f}**(母體平均參考基準線約為 25.0)
* **高風險觸發門檻**:{th_high*100:.1f}%(目前個案高風險機率:{prob_high*100:.1f}%)

---
#### 🩺 個人化生活型態衛教建議:
"""
    if daily_screen_hours >= 9.0:
        prescription += f"• **高暴露預警**:每日螢幕使用高達 {daily_screen_hours} 小時,已達重度暴露標準,建議每小時嚴格執行「20-20-20」遠眺放鬆。\n"
    if sleep_hours <= 5.5:
        prescription += f"• **修復不足預警**:每日睡眠僅 {sleep_hours} 小時,嚴重削弱眼表上皮細胞夜間修復力,此為推升風險的重要隱形推手。\n"
    if blurred_vision == "Yes":
        prescription += "• **急性徵兆預警**:近期出現視力模糊症狀,可能為睫狀肌痙攣或淚膜破裂,建議優先安排眼科驗光與角膜檢查。\n"
    if blue_light_filter == "Yes":
        prescription += "• **衛教提醒**:雖有使用抗藍光濾鏡,但根據本專案實證研究,濾鏡無法抵消長時間暴露與睡眠缺乏帶來的實質損害,請勿產生「代償性放鬆」。\n"
        
    return alert_badge, prob_dict, prescription

# 3. 建立 Gradio UI 佈局
with gr.Blocks(title="數位用眼疲勞風險即時評估系統", theme=gr.themes.Soft()) as demo:
    gr.Markdown(
        """
        # 👁️ 數位用眼疲勞(Digital Eye Strain)智慧評估系統
        ### 30 天鐵人挑戰成果:結合 LightGBM & Random Forest 軟投票集成模型與 XAI 臨床可解釋性
        """
    )
    
    with gr.Row():
        # 左側輸入控制面板
        with gr.Column(scale=1):
            gr.Markdown("### 👤 受試者基本作息與自覺症狀輸入")
            age = gr.Slider(minimum=18, maximum=75, value=24, step=1, label="年齡 (Age)")
            role = gr.Dropdown(choices=["Student", "Non-Student"], value="Student", label="身分角色 (Role)")
            daily_screen = gr.Slider(minimum=1.0, maximum=18.0, value=11.5, step=0.5, label="每日螢幕時數 (小時)")
            sleep_hours = gr.Slider(minimum=2.0, maximum=12.0, value=5.0, step=0.5, label="每日睡眠時數 (小時)")
            break_freq = gr.Slider(minimum=0, maximum=10, value=1, step=1, label="每小時休息次數 (次/小時)")
            
            with gr.Row():
                eye_dryness = gr.Slider(minimum=0, maximum=10, value=8, step=1, label="眼睛乾澀自覺分數 (0-10)")
                eye_pain = gr.Slider(minimum=0, maximum=10, value=7, step=1, label="眼睛疼痛自覺分數 (0-10)")
                
            headache_freq = gr.Slider(minimum=0, maximum=7, value=4, step=1, label="每週頭痛次數 (天/週)")
            
            with gr.Row():
                blue_filter = gr.Radio(choices=["Yes", "No"], value="Yes", label="使用抗藍光濾鏡")
                blurred = gr.Radio(choices=["Yes", "No"], value="Yes", label="近期視力模糊")
                
            btn_submit = gr.Button("🔍 立即進行智慧風險評估", variant="primary")
            
        # 右側結果與報告展示面板
        with gr.Column(scale=1):
            gr.Markdown("### 📊 智慧推論診斷結果")
            out_badge = gr.Textbox(label="系統診斷判定狀態", interactive=False)
            out_chart = gr.Label(num_top_classes=3, label="三類別預測機率分佈 (Soft Voting Probabilities)")
            out_report = gr.Markdown(label="個人化衛教處方箋")
            
    # 綁定按鈕事件
    btn_submit.click(
        fn=diagnose_eye_strain,
        inputs=[
            age, role, daily_screen, sleep_hours, 
            break_freq, eye_dryness, eye_pain, 
            headache_freq, blue_filter, blurred
        ],
        outputs=[out_badge, out_chart, out_report]
    )

# 4. 啟動 Web 服務
demo.launch(share=True, debug=False)

https://ithelp.ithome.com.tw/upload/images/20261014/20178794DRkMGgAQP4.png
https://ithelp.ithome.com.tw/upload/images/20261014/20178794RPNbBhBwhS.png
https://ithelp.ithome.com.tw/upload/images/20261014/20178794yt0YxMmH7J.png
立即進行智慧風險評估:
https://ithelp.ithome.com.tw/upload/images/20261014/201787941JqWNswyKH.png
https://ithelp.ithome.com.tw/upload/images/20261014/20178794gd5APFR4WN.png


三、 圖表解讀與客觀數據分析
本實作以 Gradio 互動式 Web 儀表板成功串接已持久化的軟投票集成模型(eye_strain_ensemble_pipeline.joblib),在點擊「立即進行智慧風險評估」後,前端即時呈現了診斷燈號、三類別預測機率條形圖與臨床個人化衛教處方箋。從輸出的介面數值中,可提煉出三項關鍵的落地實證成果:
1.即時推論機率與動態門檻機制在前端的完美復現
a.軟投票機率分佈條形圖:

  • 低度風險(Low):37%
  • 中度風險(Medium):34%
  • 高度風險(High):29%
    b.高風險動態門檻(Threshold Moving)判定邏輯:
  • 系統載入之高風險主動警示臨界值為 $\tau = 0.370$(37.0%)。
  • 該名受試者的高風險後驗機率為 29.5%(約 29%),未越過 37.0% 的主動警示門檻,因此系統未觸發紅色高風險警示狀態。
  • 系統退回低度與中度之間進行競逐,低度風險機率(37%)略高於中度風險(34%),系統診斷判定狀態顯示為
    🟢 【狀態良好】低度用眼疲勞,請繼續保持健康習慣。,與 Day 28 的 Pipeline 單元測試以及 Day 29 的 FastAPI 回傳數值完全吻合,驗證了前端到後端推論邏輯的一致性。
  1. CESI 綜合疲勞指數與臨床規則引擎的即時運算
    a.CESI 即時數值解析:
  • 根據 Day 15 所定義的特徵工程公式:
    CESI=(11.5/50)x(7+8+1)=2.3x16=36.80
  • 儀表板成功即時計算出 CESI 綜合疲勞指數:36.80。
  • 對比母體平均參考基準線(約 25.0),該數值高達 36.80,直接量化了該名受試者客觀暴露量與自覺症狀的複合負擔。

b.臨床衛教處方箋的動態生成(結合 XAI 與統計實證):

  • 高暴露預警:識別出每日螢幕使用 11.5 小時,主動給出「20-20-20」遠眺放鬆指引。
  • 修復不足預警:捕捉到睡眠僅 5 小時,指出其對眼表上皮細胞夜間修復力的損害。
  • 急性徵兆預警:針對「視力模糊(Yes)」給出就醫驗光與角膜檢查建議。
  • 濾鏡衛教提醒:受試者勾選使用了抗藍光濾鏡,處方箋即時融入 Day 16 的推論統計實證(濾鏡無顯著防護效益),明確提醒受試者切勿產生「代償性放鬆」。
  1. 30 天工程收官成果:端到端醫療級決策支援系統(CDSS)落地
  • 透過 Gradio 建立的這套原型系統,將「黑盒子機器學習演算法」包裝為「具備臨床溝通力的可解釋性介面」。
  • 從前端滑桿輸入、後端自動特徵工程(CESI 合成)、StandardScaler 縮放、軟投票集成預測、動態門檻過濾,到最終處方文字生成,全部在數十毫秒內閉環完成,圓滿達成了本次鐵人挑戰的終極目標!

上一篇
打造對外微服務!FastAPI 高效 RESTful API 搭建與 Pydantic 嚴格型別驗證
系列文
用數據守護雙眼:生活型態對視力影響的探索性資料分析 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言